/**
 * @file lv_port_indev.c
 *
 */

/*Copy this file as "lv_port_indev.c" and set this value to "1" to enable content*/
#if 1

/*********************
 *      INCLUDES
 *********************/
#include "lvgl.h"
#include "lv_port_indev.h"
#include "btn_drv.h"
#include "Arduino.h"
/*********************
 *      DEFINES
 *********************/

#define INPUT_ENABLE_TOUCHPAD          0
#define INPUT_ENABLE_MOUSE             0
#define INPUT_ENABLE_KEYPAD            0
#define INPUT_ENABLE_ENCODER           1
#define INPUT_ENABLE_BUTTON            0

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
#if INPUT_ENABLE_TOUCHPAD
static void touchpad_init(void);
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool touchpad_is_pressed(void);
static void touchpad_get_xy(lv_coord_t* x, lv_coord_t* y);
#endif

#if INPUT_ENABLE_MOUSE
static void mouse_init(void);
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static bool mouse_is_pressed(void);
static void mouse_get_xy(lv_coord_t* x, lv_coord_t* y);
#endif

#if INPUT_ENABLE_KEYPAD
static void keypad_init(void);
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static uint32_t keypad_get_key(void);
#endif

#if INPUT_ENABLE_ENCODER
static void encoder_init(void);
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static void encoder_handler(void);
#endif

#if INPUT_ENABLE_BUTTON
static void button_init(void);
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
static int8_t button_get_pressed_id(void);
static bool button_is_pressed(uint8_t id);
#endif

/**********************
 *  STATIC VARIABLES
 **********************/
#if INPUT_ENABLE_TOUCHPAD
lv_indev_t* indev_touchpad;
#endif

#if INPUT_ENABLE_MOUSE
lv_indev_t* indev_mouse;
#endif

#if INPUT_ENABLE_KEYPAD
lv_indev_t* indev_keypad;
#endif

#if INPUT_ENABLE_ENCODER
lv_indev_t* indev_encoder;
static int32_t encoder_diff;
static lv_indev_state_t encoder_state;
#endif

#if INPUT_ENABLE_BUTTON
lv_indev_t* indev_button;

/*Assign buttons to points on the screen*/
static const lv_point_t btn_points[] = {
	// 0 -- BOOT -- 翻页
	{ 225, 5 },

	// 1 -- RED -- ISO-
	{ 135, 35 },

	// 2 -- BLUE -- ISO+
	{ 211, 35 },

	// 3 -- SELECT -- 切换测光模式 AV/TV
	{ 151, 5},

	// 4 -- DOWN -- AP-
	{ 135, 65},

	// 5 -- UP -- AP+
	{ 211, 65},

	// 6 -- LEFT -- SP-
	{ 135, 95},

	// 7 -- RIGHT -- SP+
	{ 211, 95}
};
#endif


/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
 **********************/

void lv_port_indev_init(void)
{
    /**
     * Here you will find example implementation of input devices supported by LittelvGL:
     *  - Touchpad
     *  - Mouse (with cursor support)
     *  - Keypad (supports GUI usage only with key)
     *  - Encoder (supports GUI usage only with: left, right, push)
     *  - Button (external buttons to press points on the screen)
     *
     *  The `..._read()` function are only examples.
     *  You should shape them according to your hardware
     */

    static lv_indev_drv_t indev_drv;

    /*------------------
     * Touchpad
     * -----------------*/
#if INPUT_ENABLE_TOUCHPAD
    /*Initialize your touchpad if you have*/
    touchpad_init();

    /*Register a touchpad input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    indev_touchpad = lv_indev_drv_register(&indev_drv);
#endif

    /*------------------
     * Mouse
     * -----------------*/
#if INPUT_ENABLE_MOUSE
    /*Initialize your mouse if you have*/
    mouse_init();

    /*Register a mouse input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = mouse_read;
    indev_mouse = lv_indev_drv_register(&indev_drv);

    /*Set cursor. For simplicity set a HOME symbol now.*/
    lv_obj_t * mouse_cursor = lv_img_create(lv_scr_act());
    lv_img_set_src(mouse_cursor, LV_SYMBOL_HOME);
    lv_indev_set_cursor(indev_mouse, mouse_cursor);
#endif

    /*------------------
     * Keypad
     * -----------------*/
#if INPUT_ENABLE_KEYPAD
    /*Initialize your keypad or keyboard if you have*/
    keypad_init();

    /*Register a keypad input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_KEYPAD;
    indev_drv.read_cb = keypad_read;
    indev_keypad = lv_indev_drv_register(&indev_drv);

    /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
     *add objects to the group with `lv_group_add_obj(group, obj)`
     *and assign this input device to group to navigate in it:
     *`lv_indev_set_group(indev_keypad, group);`*/
#endif

	/*------------------
     * Encoder
     * -----------------*/
#if INPUT_ENABLE_ENCODER
    /*Initialize your encoder if you have*/
    encoder_init();

    /*Register a encoder input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_ENCODER;
    indev_drv.read_cb = encoder_read;
    indev_encoder = lv_indev_drv_register(&indev_drv);

    /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
     *add objects to the group with `lv_group_add_obj(group, obj)`
     *and assign this input device to group to navigate in it:
	 *`lv_indev_set_group(indev_encoder, group);`*/

	lv_group_t* group = lv_group_create();
	lv_group_set_default(group);
	lv_indev_set_group(indev_encoder, group);
#endif

    /*------------------
     * Button
     * -----------------*/
#if INPUT_ENABLE_BUTTON
    /*Initialize your button if you have*/
    button_init();

    /*Register a button input device*/
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_BUTTON;
    indev_drv.read_cb = button_read;
    indev_button = lv_indev_drv_register(&indev_drv);


    lv_indev_set_button_points(indev_button, btn_points);
#endif
}

/**********************
 *   STATIC FUNCTIONS
 **********************/

/*------------------
 * Touchpad
 * -----------------*/
#if INPUT_ENABLE_TOUCHPAD
/*Initialize your touchpad*/
static void touchpad_init(void)
{
    /*Your code comes here*/
}

/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static lv_coord_t last_x = 0;
    static lv_coord_t last_y = 0;

    /*Save the pressed coordinates and the state*/
    if(touchpad_is_pressed()) {
        touchpad_get_xy(&last_x, &last_y);
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    /*Set the last pressed coordinates*/
    data->point.x = last_x;
    data->point.y = last_y;
}

/*Return true is the touchpad is pressed*/
static bool touchpad_is_pressed(void)
{
    /*Your code comes here*/

    return false;
}

/*Get the x and y coordinates if the touchpad is pressed*/
static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/

    (*x) = 0;
    (*y) = 0;
}
#endif

/*------------------
 * Mouse
 * -----------------*/
#if INPUT_ENABLE_MOUSE
/*Initialize your mouse*/
static void mouse_init(void)
{
    /*Your code comes here*/
}

/*Will be called by the library to read the mouse*/
static void mouse_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    /*Get the current x and y coordinates*/
    mouse_get_xy(&data->point.x, &data->point.y);

    /*Get whether the mouse button is pressed or released*/
    if(mouse_is_pressed()) {
        data->state = LV_INDEV_STATE_PR;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }
}

/*Return true is the mouse button is pressed*/
static bool mouse_is_pressed(void)
{
    /*Your code comes here*/

    return false;
}

/*Get the x and y coordinates if the mouse is pressed*/
static void mouse_get_xy(lv_coord_t * x, lv_coord_t * y)
{
    /*Your code comes here*/

    (*x) = 0;
    (*y) = 0;
}
#endif

/*------------------
 * Keypad
 * -----------------*/
#if INPUT_ENABLE_KEYPAD
/*Initialize your keypad*/
static void keypad_init(void)
{
    /*Your code comes here*/
	// NOTE: 初始化已经放在 button_drv.c 文件中
	LV_LOG_USER("keypad_init");
}

#include "btn_drv.h"

/*Will be called by the library to read the mouse*/
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static uint32_t last_key = 0;

    /*Get the current x and y coordinates*/
    mouse_get_xy(&data->point.x, &data->point.y); // TODO: 对于 keypad 来说应该没有用

    /*Get whether the a key is pressed and save the pressed key*/
    uint32_t act_key = keypad_get_key(); //
    if(act_key != 0) {
        data->state = LV_INDEV_STATE_PR;

        /*Translate the keys to LVGL control characters according to your key definitions*/
		// TODO: 修改对应的按键
        switch(act_key) {
            case 1:
                act_key = LV_KEY_ENTER;
                break;
            case 2:
                act_key = LV_KEY_LEFT;
                break;
            case 3:
                act_key = LV_KEY_RIGHT;
                break;
            default:
                break;
        }

        last_key = act_key;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    data->key = last_key;
}

/*Get the currently being pressed key.  0 if no key is pressed*/
static uint32_t keypad_get_key(void)
{
    /*Your code comes here*/
	uint32_t key = 0;

	return key;
}
#endif

/*------------------
 * Encoder
 * -----------------*/
#if INPUT_ENABLE_ENCODER
/*Initialize your keypad*/
static void encoder_init(void)
{
    /*Your code comes here*/
}

/*Will be called by the library to read the encoder*/
static void encoder_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
	/* 按键实现旋转编码器，参考韦东山 bilibili 视频课程 4-5_LVGL-MCU 进阶教程之通过3个按键替代编码器 */
	// https://www.bilibili.com/video/BV1HFUbYjESh/?spm_id_from=333.999.list.card_archive.click&vd_source=8f2bbf56b70c541bec2ea0b9f102ebee
	static uint8_t key_state_changed = 0;

	if (btn_is_pressed(BTN_ID_0_BOOT)) { // 按下
		encoder_diff = 0;
		encoder_state = LV_INDEV_STATE_PRESSED;
		goto flag_update_enc_state;
	}

	if (btn_is_pressed(BTN_ID_1_RED)) { // 左旋 -- 后退
		encoder_diff -= 1;
		encoder_state = LV_INDEV_STATE_RELEASED;
		goto flag_update_enc_state;
	}

	if (btn_is_pressed(BTN_ID_2_BLUE)) { // 右旋 -- 前进
		encoder_diff += 1;
		encoder_state = LV_INDEV_STATE_RELEASED;
		goto flag_update_enc_state;
	}

	// 默认情况，没有按键按下，则释放状态
	encoder_diff = 0;
	encoder_state = LV_INDEV_STATE_RELEASED;


flag_update_enc_state:
	data->enc_diff = encoder_diff;
    data->state = encoder_state;
}

/*Call this function in an interrupt to process encoder events (turn, press)*/
static void encoder_handler(void)
{
    /*Your code comes here*/

    encoder_diff += 0;
    encoder_state = LV_INDEV_STATE_REL;
}
#endif

/*------------------
 * Button
 * -----------------*/
#if INPUT_ENABLE_BUTTON
/*Initialize your buttons*/
static void button_init(void)
{
	/*Your code comes here*/
	// setup_btn(); // 在别处先调用
}

/*Will be called by the library to read the button*/
static void button_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{

    static uint8_t last_btn = 0;

    /*Get the pressed button's ID*/
    int8_t btn_act = button_get_pressed_id();

    if(btn_act >= 0) {
        data->state = LV_INDEV_STATE_PR;
        last_btn = btn_act;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    /*Save the last pressed button's ID*/
    data->btn_id = last_btn;
}

/*Get ID  (0, 1, 2 ..) of the pressed button*/
static int8_t button_get_pressed_id(void)
{
    uint8_t i;

    /*Check to buttons see which is being pressed (assume there are 2 buttons)*/
    for(i = 0; i < sizeof(btn_points)/sizeof(btn_points[0]); i++) {
        /*Return the pressed button's ID*/
        if(button_is_pressed(i)) {
            return i;
        }
    }

    /*No button pressed*/
    return -1;
}

/*Test if `id` button is pressed or not*/
static bool button_is_pressed(uint8_t id)
{

    /*Your code comes here*/
	return btn_is_pressed(id);
}
#endif
#else /*Enable this file at the top*/

/*This dummy typedef exists purely to silence -Wpedantic.*/
typedef int keep_pedantic_happy;
#endif
